cmake_minimum_required(VERSION 3.15)

# 编译器版本选择选项（必须在project()之前设置）
set(GCC_VERSION "" CACHE STRING "指定GCC版本 (例如: 9, 10, 11, 12, 13)")
set(CROSS_COMPILE "" CACHE STRING "交叉编译前缀 (例如: arm-linux-gnueabihf)")

# 编译器设置逻辑（必须在project()之前）
if(CROSS_COMPILE)
  # 交叉编译模式
  set(CMAKE_C_COMPILER ${CROSS_COMPILE}-gcc CACHE PATH "C compiler")
  set(CMAKE_CXX_COMPILER ${CROSS_COMPILE}-g++ CACHE PATH "C++ compiler")
  message(STATUS "使用交叉编译工具链: ${CROSS_COMPILE}")
elseif(GCC_VERSION)
  # 指定GCC版本
  set(CMAKE_C_COMPILER gcc-${GCC_VERSION} CACHE PATH "C compiler")
  set(CMAKE_CXX_COMPILER g++-${GCC_VERSION} CACHE PATH "C++ compiler")
  message(STATUS "使用指定版本的GCC: ${GCC_VERSION}")
else()
  # 使用系统默认编译器
  message(STATUS "使用系统默认编译器")
endif()

# 调用project()以启用C++语言支持
# 注意：必须在设置编译器之后调用project()，这样CMake才会使用我们指定的编译器
project(cpp_features VERSION 1.0.0 LANGUAGES CXX)

# 显示编译器信息（project()之后才能获取正确的编译器信息）
message(STATUS "C编译器: ${CMAKE_C_COMPILER}")
message(STATUS "C++编译器: ${CMAKE_CXX_COMPILER}")
message(STATUS "CMake检测到的编译器ID: ${CMAKE_CXX_COMPILER_ID}")
message(STATUS "CMake检测到的编译器版本: ${CMAKE_CXX_COMPILER_VERSION}")

# 验证编译器是否可用并显示版本信息
execute_process(
  COMMAND ${CMAKE_CXX_COMPILER} --version
  OUTPUT_VARIABLE COMPILER_VERSION_OUTPUT
  ERROR_VARIABLE COMPILER_VERSION_ERROR
  RESULT_VARIABLE COMPILER_VERSION_RESULT
)

if(NOT COMPILER_VERSION_RESULT EQUAL 0)
  message(FATAL_ERROR "指定的编译器不可用: ${CMAKE_CXX_COMPILER}")
else()
  string(REGEX MATCH "[0-9]+\\.[0-9]+\\.[0-9]+" COMPILER_VERSION_STRING "${COMPILER_VERSION_OUTPUT}")
  message(STATUS "实际编译器版本（通过--version获取）: ${COMPILER_VERSION_STRING}")
  
  # 验证CMake检测到的版本与实际版本是否一致
  if(CMAKE_CXX_COMPILER_VERSION AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS "${COMPILER_VERSION_STRING}")
    message(WARNING "CMake检测到的编译器版本(${CMAKE_CXX_COMPILER_VERSION})与实际版本(${COMPILER_VERSION_STRING})不一致")
    message(WARNING "这可能是因为CMake缓存了旧的编译器信息，请清除build目录后重新配置")
  endif()
endif()

# 设置C++标准（主项目使用C++23，但子模块会各自设置自己的标准）
# 注意：不要在这里设置CMAKE_CXX_STANDARD，让子模块自己设置
# 这样可以确保每个模块使用正确的C++标准
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

# 添加编译选项
if(MSVC)
  add_compile_options(/W4)
else()
  add_compile_options(-Wall -Wextra -Wpedantic)
endif()

# 根据编译器版本检查C++23支持
# 注意：使用实际检测到的版本号
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
  if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "11.0")
    message(WARNING "GCC ${CMAKE_CXX_COMPILER_VERSION} 不完全支持C++23，建议使用GCC 11或更高版本")
    set(CMAKE_CXX_STANDARD 20)
    message(STATUS "降级到C++20标准")
  else()
    message(STATUS "GCC ${CMAKE_CXX_COMPILER_VERSION} 支持C++23")
  endif()
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
  if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "12.0")
    message(WARNING "Clang ${CMAKE_CXX_COMPILER_VERSION} 不完全支持C++23，建议使用Clang 12或更高版本")
    set(CMAKE_CXX_STANDARD 20)
    message(STATUS "降级到C++20标准")
  else()
    message(STATUS "Clang ${CMAKE_CXX_COMPILER_VERSION} 支持C++23")
  endif()
endif()

set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

# ============================================================================
# C++标准特性编译选项
# ============================================================================
# 用户可以通过以下选项选择编译哪些C++标准特性
# 例如：cmake -DBUILD_CPP14=ON -DBUILD_CPP17=OFF ..
# 或者：cmake -DBUILD_ALL_STANDARDS=ON ..

option(BUILD_CPP14 "编译C++14特性演示" ON)
option(BUILD_CPP17 "编译C++17特性演示" ON)
option(BUILD_CPP20 "编译C++20特性演示" ON)
option(BUILD_CPP23 "编译C++23特性演示" ON)

# 便捷选项：一次性启用所有标准
option(BUILD_ALL_STANDARDS "编译所有C++标准特性（覆盖单独选项）" OFF)

# 如果设置了BUILD_ALL_STANDARDS，则启用所有标准
if(BUILD_ALL_STANDARDS)
  set(BUILD_CPP14 ON)
  set(BUILD_CPP17 ON)
  set(BUILD_CPP20 ON)
  set(BUILD_CPP23 ON)
  message(STATUS "已启用所有C++标准特性编译")
endif()

# 显示当前选择的编译选项
message(STATUS "========================================")
message(STATUS "C++标准特性编译选项:")
message(STATUS "  BUILD_CPP14: ${BUILD_CPP14}")
message(STATUS "  BUILD_CPP17: ${BUILD_CPP17}")
message(STATUS "  BUILD_CPP20: ${BUILD_CPP20}")
message(STATUS "  BUILD_CPP23: ${BUILD_CPP23}")
message(STATUS "========================================")

# 根据选项添加子目录（每个子目录会创建自己的可执行文件）
if(BUILD_CPP14)
  message(STATUS "添加C++14特性子目录")
  add_subdirectory(cpp14)
endif()

if(BUILD_CPP17)
  message(STATUS "添加C++17特性子目录")
  add_subdirectory(cpp17)
endif()

if(BUILD_CPP20)
  message(STATUS "添加C++20特性子目录")
  add_subdirectory(cpp20)
endif()

if(BUILD_CPP23)
  message(STATUS "添加C++23特性子目录")
  add_subdirectory(cpp23)
endif()

# 可选：添加主可执行文件（汇总所有标准版本）
# 如果不需要汇总版本，可以注释掉这部分
option(BUILD_MAIN_EXECUTABLE "编译汇总所有标准的主可执行文件" ON)

if(BUILD_MAIN_EXECUTABLE)
  # 检查是否至少有一个标准被启用
  if(BUILD_CPP14 OR BUILD_CPP17 OR BUILD_CPP20 OR BUILD_CPP23)
    add_executable(cpp_features main.cpp)
    # 主可执行文件需要C++17（因为使用了结构化绑定）
    target_compile_features(cpp_features PUBLIC cxx_std_17)
    
    # 添加预处理器定义，让main.cpp知道哪些特性被编译了
    # 注意：必须使用PUBLIC或PRIVATE关键字，确保正确的链接顺序
    if(BUILD_CPP14)
      target_compile_definitions(cpp_features PRIVATE BUILD_CPP14)
      target_link_libraries(cpp_features PUBLIC cpp14_features_lib)
    endif()
    
    if(BUILD_CPP17)
      target_compile_definitions(cpp_features PRIVATE BUILD_CPP17)
      target_link_libraries(cpp_features PUBLIC cpp17_features_lib)
    endif()
    
    if(BUILD_CPP20)
      target_compile_definitions(cpp_features PRIVATE BUILD_CPP20)
      target_link_libraries(cpp_features PUBLIC cpp20_features_lib)
    endif()
    
    if(BUILD_CPP23)
      target_compile_definitions(cpp_features PRIVATE BUILD_CPP23)
      target_link_libraries(cpp_features PUBLIC cpp23_features_lib)
    endif()
    
    message(STATUS "主可执行文件(cpp_features)已配置")
  else()
    message(WARNING "没有启用任何C++标准特性，跳过主可执行文件编译")
  endif()
endif()